////////////////////////////////////////////////////////////////////////////////
/// @file    fsmc_nor.c
/// @author  AE TEAM
/// @brief   THIS FILE PROVIDES ALL THE SYSTEM FUNCTIONS.
////////////////////////////////////////////////////////////////////////////////
/// @attention
///
/// THE EXISTING FIRMWARE IS ONLY FOR REFERENCE, WHICH IS DESIGNED TO PROVIDE
/// CUSTOMERS WITH CODING INFORMATION ABOUT THEIR PRODUCTS SO THEY CAN SAVE
/// TIME. THEREFORE, MINDMOTION SHALL NOT BE LIABLE FOR ANY DIRECT, INDIRECT OR
/// CONSEQUENTIAL DAMAGES ABOUT ANY CLAIMS ARISING OUT OF THE CONTENT OF SUCH
/// HARDWARE AND/OR THE USE OF THE CODING INFORMATION CONTAINED HEREIN IN
/// CONNECTION WITH PRODUCTS MADE BY CUSTOMERS.
///
/// <H2><CENTER>&COPY; COPYRIGHT MINDMOTION </CENTER></H2>
////////////////////////////////////////////////////////////////////////////////

// Define to prevent recursive inclusion
#define _FSMC_NOR_C_

// Files includes
#include "fsmc_nor.h"
#include "delay.h"

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup MM32_Example_Layer
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup FSMC_NOR
/// @{

////////////////////////////////////////////////////////////////////////////////
/// @addtogroup FSMC_NOR_Exported_Constants
/// @{


// Private define
#define NOR_FLASH_START_ADDR       ((u32)0x60000000)
#define NOR_FLASH_END_ADDR         ((u32)0x63FFFFFF)

//// Delay definition
#define BlockErase_Timeout         ((u32)0x00A00000)
#define ChipErase_Timeout          ((u32)0x30000000)
#define Program_Timeout            ((u32)0x00000100)

#define ADDR_SHIFT(A)              (NOR_FLASH_START_ADDR + (2 * (A)))
#define NOR_WRITE(Address, Data)   (*(vu16 *)(Address) = (Data))

//#define BUFFER_SIZE                0x400
#define BUFFER_SIZE                50
#define WRITE_READ_ADDR            0x8000

// Private variables
static u16 TxBuffer[BUFFER_SIZE];
static u16 RxBuffer[BUFFER_SIZE];

////////////////////////////////////////////////////////////////////////////////
/// @brief  Configures the FSMC and GPIOs to interface with the NOR memory.
/// @note   This function must be called before any write/read operation on the NOR.
/// @param  None.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void FSMC_GPIO_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_StructInit(&GPIO_InitStructure);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB | RCC_AHBENR_GPIOC | RCC_AHBENR_GPIOA | RCC_AHBENR_GPIOD | RCC_AHBENR_GPIOE | RCC_AHBENR_GPIOF | RCC_AHBENR_GPIOG, ENABLE);


    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_12);                       //NADV
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource0, GPIO_AF_12);                       //DA2
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource1, GPIO_AF_12);                       //DA3
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_12);                       //SDIO_CMD
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource3, GPIO_AF_12);                       //CLK
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource4, GPIO_AF_12);                       //NOE
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource5, GPIO_AF_12);                       //NWE
//    GPIO_PinAFConfig(GPIOD, GPIO_PinSource6, GPIO_AF_12);                       //NWAIT
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource7, GPIO_AF_12);                       //NE1
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource8, GPIO_AF_12);                       //DA13
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource9, GPIO_AF_12);                       //DA14
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource10, GPIO_AF_12);                      //DA15
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource11, GPIO_AF_12);                      //A16
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource12, GPIO_AF_12);                      //A17
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource13, GPIO_AF_12);                      //A18
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource14, GPIO_AF_12);                      //DA0
    GPIO_PinAFConfig(GPIOD, GPIO_PinSource15, GPIO_AF_12);                      //DA1
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource0, GPIO_AF_12);                       //NBL0
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource1, GPIO_AF_12);                       //NBL1
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource2, GPIO_AF_12);                       //A23
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource3, GPIO_AF_12);                       //A19
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource4, GPIO_AF_12);                       //A20
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource5, GPIO_AF_12);                       //A21
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource6, GPIO_AF_12);                       //A22
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource7, GPIO_AF_12);                       //DA4
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource8, GPIO_AF_12);                       //DA5
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource9, GPIO_AF_12);                       //DA6
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource10, GPIO_AF_12);                      //DA7
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource11, GPIO_AF_12);                      //DA8
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource12, GPIO_AF_12);                      //DA9
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_12);                      //DA10
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource14, GPIO_AF_12);                      //DA11
    GPIO_PinAFConfig(GPIOE, GPIO_PinSource15, GPIO_AF_12);                      //DA12

    GPIO_PinAFConfig(GPIOF, GPIO_PinSource0, GPIO_AF_12);                       //A0
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource1, GPIO_AF_12);                       //A1
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource2, GPIO_AF_12);                       //A2
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource3, GPIO_AF_12);                       //A3
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource4, GPIO_AF_12);                       //A4
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource5, GPIO_AF_12);                       //A5
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource6, GPIO_AF_12);                       //NIORD
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource7, GPIO_AF_12);                       //NREG
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource8, GPIO_AF_12);                       //NIOWR
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource9, GPIO_AF_12);                       //CD
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource10, GPIO_AF_12);                      //INTR
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource11, GPIO_AF_12);                      //NIOS16
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource12, GPIO_AF_12);                      //A6
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource13, GPIO_AF_12);                      //A7
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource14, GPIO_AF_12);                      //A8
    GPIO_PinAFConfig(GPIOF, GPIO_PinSource15, GPIO_AF_12);                      //A9

    GPIO_PinAFConfig(GPIOG, GPIO_PinSource0, GPIO_AF_12);                       //A10
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource1, GPIO_AF_12);                       //A11
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource2, GPIO_AF_12);                       //A12
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource3, GPIO_AF_12);                       //A13
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource4, GPIO_AF_12);                       //A14
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource5, GPIO_AF_12);                       //A15
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource6, GPIO_AF_12);                       //INT2
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource7, GPIO_AF_12);                       //INT3
    //GPIO_PinAFConfig(GPIOG,GPIO_PinSource8,GPIO_AF_12);
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource9, GPIO_AF_12);                       //FMC_NE2/FMC_NCE3
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource10, GPIO_AF_12);                      //FMC_NCE4_1/FMC_NE3
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource11, GPIO_AF_12);                      //FMC_NCE4_2
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource12, GPIO_AF_12);                      //FMC_NE4
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource13, GPIO_AF_12);                      //A24
    GPIO_PinAFConfig(GPIOG, GPIO_PinSource14, GPIO_AF_12);                      //A25
//  GPIO_PinAFConfig(GPIOG,GPIO_PinSource15,GPIO_AF_12);

    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_FLOATING;
    GPIO_Init(GPIOD, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOE, &GPIO_InitStructure);



    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOF, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_All;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOG, &GPIO_InitStructure);



    GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

}


////////////////////////////////////////////////////////////////////////////////
/// @brief  Reads NOR memory's Manufacturer and Device Code.
/// @param  NOR_ID: pointer to a NOR_IDTypeDef structure which will hold
///         the Manufacturer and Device Code.
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void FSMC_NOR_ReadID(NOR_IDTypeDef* NOR_ID)
{
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x0090);

    NOR_ID->Manufacturer_Code = *(vu16*) ADDR_SHIFT(0x0000);
    NOR_ID->Device_Code1 = *(vu16*) ADDR_SHIFT(0x0001);
    NOR_ID->Device_Code2 = *(vu16*) ADDR_SHIFT(0x000E);
    NOR_ID->Device_Code3 = *(vu16*) ADDR_SHIFT(0x000F);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Erases the specified Nor memory block.
/// @param  BlockAddr: address of the block to erase.
/// @retval NOR_Status:The returned value can be: NOR_SUCCESS, NOR_ERROR
///         or NOR_TIMEOUT
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_EraseBlock(u32 BlockAddr)
{
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x0080);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE((NOR_FLASH_START_ADDR + BlockAddr), 0x30);

    return (FSMC_NOR_GetStatus(BlockErase_Timeout));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Erases the entire chip.
/// @param  None.
/// @retval NOR_Status:The returned value can be: NOR_SUCCESS, NOR_ERROR
///         or NOR_TIMEOUT
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_EraseChip(void)
{
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x0080);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x0010);

    return (FSMC_NOR_GetStatus(ChipErase_Timeout));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Writes a half-word to the NOR memory.
/// @param  WriteAddr : NOR memory internal address to write to.
/// @param  Data : Data to write.
/// @retval NOR_Status:The returned value can be: NOR_SUCCESS, NOR_ERROR
///         or NOR_TIMEOUT
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_WriteHalfWord(u32 WriteAddr, u16 Data)
{
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00A0);
    NOR_WRITE((NOR_FLASH_START_ADDR + WriteAddr), Data);

    return (FSMC_NOR_GetStatus(Program_Timeout));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Writes a half-word buffer to the FSMC NOR memory.
/// @param  pBuffer : pointer to buffer.
/// @param  WriteAddr : NOR memory internal address from which the data
///         will be written.
/// @param  NumHalfwordToWrite : number of Half words to write.
/// @retval NOR_Status:The returned value can be: NOR_SUCCESS, NOR_ERROR
///         or NOR_TIMEOUT
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_WriteBuffer(u16* pBuffer, u32 WriteAddr, u32 NumHalfwordToWrite)
{
    NOR_Status status = NOR_ONGOING;

    do {
        // Transfer data to the memory
        status = FSMC_NOR_WriteHalfWord(WriteAddr, *pBuffer++);
        WriteAddr = WriteAddr + 2;
        NumHalfwordToWrite--;
    } while((status == NOR_SUCCESS) && (NumHalfwordToWrite != 0));

    return (status);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Writes a half-word buffer to the FSMC NOR memory.
/// @note   This function must be used only with S29GL128P NOR memory.
/// @param  pBuffer : pointer to buffer.
/// @param  WriteAddr: NOR memory internal address from which the data
///         will be written.
/// @param  NumHalfwordToWrite: number of Half words to write.
///         The maximum allowed value is 32 Half words (64 bytes).
/// @retval NOR_Status:The returned value can be: NOR_SUCCESS, NOR_ERROR
///         or NOR_TIMEOUT
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_ProgramBuffer(u16* pBuffer, u32 WriteAddr, u32 NumHalfwordToWrite)
{
    u32 lastloadedaddress = 0x00;
    u32 currentaddress = 0x00;
    u32 endaddress = 0x00;

    // Initialize variables
    currentaddress = WriteAddr;
    endaddress = WriteAddr + NumHalfwordToWrite - 1;
    lastloadedaddress = WriteAddr;

    // Issue unlock command sequence
    NOR_WRITE(ADDR_SHIFT(0x00555), 0x00AA);

    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);

    //Write Write Buffer Load Command
    NOR_WRITE(ADDR_SHIFT(WriteAddr), 0x0025);
    NOR_WRITE(ADDR_SHIFT(WriteAddr), (NumHalfwordToWrite - 1));

    // Load Data into NOR Buffer
    while(currentaddress <= endaddress) {
        // Store last loaded address & data value (for polling)
        lastloadedaddress = currentaddress;

        NOR_WRITE(ADDR_SHIFT(currentaddress), *pBuffer++);
        currentaddress += 1;
    }

    NOR_WRITE(ADDR_SHIFT(lastloadedaddress), 0x29);

    return(FSMC_NOR_GetStatus(Program_Timeout));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  Reads a half-word from the NOR memory.
/// @param  ReadAddr : NOR memory internal address to read from.
/// @retval Half-word read from the NOR memory
////////////////////////////////////////////////////////////////////////////////
u16 FSMC_NOR_ReadHalfWord(u32 ReadAddr)
{
    NOR_WRITE(ADDR_SHIFT(0x00555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x002AA), 0x0055);
    NOR_WRITE((NOR_FLASH_START_ADDR + ReadAddr), 0x00F0 );

    return (*(vu16*)((NOR_FLASH_START_ADDR + ReadAddr)));
}

////////////////////////////////////////////////////////////////////////////////
/// @brief   Reads a block of data from the FSMC NOR memory.
/// @param   pBuffer : pointer to the buffer that receives the data read
///          from the NOR memory.
///          ReadAddr : NOR memory internal address to read from.
///          NumHalfwordToRead : number of Half word to read.
/// @retval  None
////////////////////////////////////////////////////////////////////////////////
void FSMC_NOR_ReadBuffer(u16* pBuffer, u32 ReadAddr, u32 NumHalfwordToRead)
{
    NOR_WRITE(ADDR_SHIFT(0x0555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x02AA), 0x0055);
    NOR_WRITE((NOR_FLASH_START_ADDR + ReadAddr), 0x00F0);

    for(; NumHalfwordToRead != 0x00; NumHalfwordToRead--) { // while there is data to read
        // Read a Halfword from the NOR
        *pBuffer++ = *(vu16*)((NOR_FLASH_START_ADDR + ReadAddr));
        ReadAddr = ReadAddr + 2;
    }
}

////////////////////////////////////////////////////////////////////////////////
/// @brief   Returns the NOR memory to Read mode.
/// @param   None
/// Output   None
/// @retval  NOR_SUCCESS
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_ReturnToReadMode(void)
{
    NOR_WRITE(NOR_FLASH_START_ADDR, 0x00F0);

    return (NOR_SUCCESS);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief    Returns the NOR memory to Read mode and resets the errors in
///           the NOR memory Status Register.
/// @param    None
/// @retval   NOR_SUCCESS
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_Reset(void)
{
    NOR_WRITE(ADDR_SHIFT(0x00555), 0x00AA);
    NOR_WRITE(ADDR_SHIFT(0x002AA), 0x0055);
    NOR_WRITE(NOR_FLASH_START_ADDR, 0x00F0);

    return (NOR_SUCCESS);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief   Returns the NOR operation status.
/// @param   Timeout: NOR progamming Timeout
/// @retval  NOR_Status:The returned value can be: NOR_SUCCESS, NOR_ERROR
///          or NOR_TIMEOUT
////////////////////////////////////////////////////////////////////////////////
NOR_Status FSMC_NOR_GetStatus(u32 Timeout)
{
    u16 val1 = 0x00, val2 = 0x00;
    NOR_Status status = NOR_ONGOING;
    u32 timeout = Timeout;

    // Poll on NOR memory Ready/Busy signal
    while((GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) != RESET) && (timeout > 0)) {
        timeout--;
    }

    timeout = Timeout;

    while((GPIO_ReadInputDataBit(GPIOD, GPIO_Pin_6) == RESET) && (timeout > 0)) {
        timeout--;
    }

    //Get the NOR memory operation status
    while((Timeout != 0x00) && (status != NOR_SUCCESS)) {
        Timeout--;

        // Read DQ6 and DQ5
        val1 = *(vu16*)(NOR_FLASH_START_ADDR);
        val2 = *(vu16*)(NOR_FLASH_START_ADDR);

        // If DQ6 did not toggle between the two reads then return NOR_Success
        if((val1 & 0x0040) == (val2 & 0x0040)) {
            return NOR_SUCCESS;
        }

        if((val1 & 0x0020) != 0x0020) {
            status = NOR_ONGOING;
        }

        val1 = *(vu16*)(NOR_FLASH_START_ADDR);
        val2 = *(vu16*)(NOR_FLASH_START_ADDR);

        if((val1 & 0x0040) == (val2 & 0x0040)) {
            return NOR_SUCCESS;
        }
        else if((val1 & 0x0020) == 0x0020) {
            return NOR_ERROR;
        }
    }

    if(Timeout == 0x00) {
        status = NOR_TIMEOUT;
    }

    // Return the operation status
    return (status);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief   RCC configuration
/// @param   None
/// @retval  None
////////////////////////////////////////////////////////////////////////////////
void RCC_ConfigInit(void)
{
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOA | RCC_AHBENR_GPIOB | RCC_AHBENR_GPIOC | RCC_AHBENR_GPIOD | RCC_AHBENR_GPIOE, ENABLE);
    RCC->AHB3ENR |= 0x01; //enable FSMCEN
    RCC->APB2ENR |= 0x1 << 14; //open sys_cfg clk
}
////////////////////////////////////////////////////////////////////////////////
/// @brief   Initialize FSMC_NOR
/// @param   None
/// @retval  None
////////////////////////////////////////////////////////////////////////////////
void FSMC_NOR_Init(void)
{

    FSMC_InitTypeDef  FSMC_InitStructure;
    FSMC_NORSRAM_Bank_InitTypeDef  FSMC_BankInitStructure;

    FSMC_NORSRAM_BankStructInit(&FSMC_BankInitStructure);
    FSMC_NORSRAMStructInit(&FSMC_InitStructure);

    RCC_AHB3PeriphClockCmd(RCC_AHB3ENR_FSMC, ENABLE);                           //enable FSMCEN
    FSMC_BankInitStructure.FSMC_SMReadPipe    = 0;                             // SM_read_pipe [1:0] the cycle of latch read data, namely the cycle of hready_RESP pull up
    FSMC_BankInitStructure.FSMC_ReadyMode     = 0;                             // Select whether the Hready_RESP signal comes from inside the FSMC IP or from an external DEVICE.
    //Only for write and read external DEVICE operations. 0: Internal FSMC 1: External DEVICE(i.e. from FSMC_NWAIT)
    FSMC_BankInitStructure.FSMC_WritePeriod   = 15;                            // Write operation cycle
    FSMC_BankInitStructure.FSMC_WriteHoldTime = 3;                             // Address/data retention time during write operations
    FSMC_BankInitStructure.FSMC_AddrSetTime   = 3;                             // Address setup time
    FSMC_BankInitStructure.FSMC_ReadPeriod    = 15;                            // Read operation cycle
    FSMC_BankInitStructure.FSMC_DataWidth     = FSMC_DataWidth_16bits;
    FSMC_NORSRAM_Bank_Init(&FSMC_BankInitStructure, FSMC_NORSRAM_BANK0);
    FSMC_InitStructure.FSMC_Mode = FSMC_Mode_NorFlash;

    FSMC_InitStructure.FSMC_TimingRegSelect = FSMC_TimingRegSelect_0;
    FSMC_InitStructure.FSMC_MemSize = FSMC_MemSize_64MB;
    FSMC_InitStructure.FSMC_MemType = FSMC_MemType_FLASH;                       //FSMC_MemType_NorSRAM;                     //
    FSMC_InitStructure.FSMC_AddrDataMode = FSMC_AddrDataDeMUX;


    FSMC_NORSRAMInit(&FSMC_InitStructure);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief  NORFLASH nReset GPIO configuration
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void NORFLASH_nRST_Pin_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    //set PC6 as NORFLASH_nRST Pin
    RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOC, ENABLE);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    GPIO_SetBits(GPIOC, GPIO_Pin_6);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief  Reset NORFLASH Controler
/// @param  None
/// @retval None.
////////////////////////////////////////////////////////////////////////////////
void NORFLASH_nRST_Setting(void)
{
    GPIO_SetBits(GPIOC, GPIO_Pin_6);
    DELAY_Ms(1);
    GPIO_ResetBits(GPIOC, GPIO_Pin_6);
    DELAY_Ms(5);
    GPIO_SetBits(GPIOC, GPIO_Pin_6);
    DELAY_Ms(120);
}
////////////////////////////////////////////////////////////////////////////////
/// @brief   NOR Test
/// @param   None
/// @retval  None
////////////////////////////////////////////////////////////////////////////////
void FSMC_NOR_Test(void)
{
    u16 index;
    NOR_IDTypeDef NOR_ID;
    RCC_ConfigInit();
    NORFLASH_nRST_Pin_Config();
    FSMC_GPIO_Init();
    // Initialize the FSMC NOR Flash Interface
    FSMC_NOR_Init();
    NORFLASH_nRST_Setting();
    DELAY_Ms(300);
    // Set the NOR read modes
    FSMC_NOR_ReturnToReadMode();

    FSMC_NOR_ReadID(&NOR_ID);
    printf("Nor Flash ID = %04X,%04X,%04X,%04X  ", NOR_ID.Manufacturer_Code, NOR_ID.Device_Code1,
           NOR_ID.Device_Code2, NOR_ID.Device_Code3 );
    FSMC_NOR_ReturnToReadMode();

    if( ( NOR_ID.Manufacturer_Code == 0x0001 ) && (NOR_ID.Device_Code1 == 0x227E) &&
            ( NOR_ID.Device_Code2 == 0x2212 ) && ( NOR_ID.Device_Code3 == 0x2200 ) ) {
        printf("Type = AM29LV128ML\r\n");
    }
    else if ( ( NOR_ID.Manufacturer_Code == 0x0001 ) && ( NOR_ID.Device_Code1 == 0x227E ) &&
              ( NOR_ID.Device_Code2 == 0x2221 ) && ( NOR_ID.Device_Code3 == 0x2201 ) ) {
        printf("Type = S29GL128P\r\n");
    }
    else if ( ( NOR_ID.Manufacturer_Code == 0x0020 ) && ( NOR_ID.Device_Code1 == 0x227E ) &&
              ( NOR_ID.Device_Code2 == 0x2220 ) && ( NOR_ID.Device_Code3 == 0x2200 ) ) {
        printf("Type = M29DW128F\r\n");
    }
    else {
        printf("Type = Unknow\r\n");
    }

    // Erase the NOR memory block to write on
    FSMC_NOR_EraseBlock(WRITE_READ_ADDR);

    // Write data to FSMC NOR memory
    // Fill the buffer to send
    for (index = 0; index < BUFFER_SIZE; index++ ) {
        TxBuffer[index] = index + 0x3210;
    }

    FSMC_NOR_WriteBuffer(TxBuffer, WRITE_READ_ADDR, BUFFER_SIZE);

    // Read data from FSMC NOR memory
    FSMC_NOR_ReadBuffer(RxBuffer, WRITE_READ_ADDR, BUFFER_SIZE);

    for (index = 0; index < BUFFER_SIZE; index++ ) {
        printf("Read Data:0x%x\r\n", RxBuffer[index]);
    }

    if( memcmp( (char*)TxBuffer, (char*)RxBuffer, BUFFER_SIZE ) == 0 ) {
        printf("Nor Flash is OK \r\n");
    }
    else {
        printf("Nor Flash is error \r\n");
    }
}

/// @}

/// @}

/// @}
